#include "inc/esp_wifi_webserver.h"
#include "inc/esp_wifi_scan.h"
#include "inc/index.h"
#include "E:\app\Espressif\frameworks\esp-idf-v5.0.1\components\esp_wifi\include\esp_wifi.h"
#include "E:\app\Espressif\frameworks\esp-idf-v5.0.1\components\esp_http_server\include\esp_http_server.h"


static const char *TAG = "webserver";
//char ScanResult[512];
char* ScanResult = NULL;

void wifi_scan_again_ssid(void)
{
    uint16_t number = DEFAULT_SCAN_LIST_SIZE;
    wifi_ap_record_t ap_info[DEFAULT_SCAN_LIST_SIZE];
    uint16_t ap_count = 0;
    memset(ap_info, 0, sizeof(ap_info));

    esp_wifi_scan_start(NULL, true);
    esp_wifi_scan_get_ap_records(&number, ap_info);
    esp_wifi_scan_get_ap_num(&ap_count);
    char temp_ssid[256] = {0};
    ScanResult = (char*)malloc(512);
    memset(ScanResult,0,512);
    ScanResult[0] = '[';

    for(int i = 0; (i < DEFAULT_SCAN_LIST_SIZE) && (i < ap_count); i++) {
        sprintf(temp_ssid, "{\"ssid\":\"%s\",\"dbm\":\"%d\",\"type\":\"%d\"},",
        ap_info[i].ssid,ap_info[i].rssi,
        (ap_info[i].authmode == WIFI_AUTH_OPEN?1:0));
        strcat(ScanResult, temp_ssid);
        memset(temp_ssid,0,256);
    }
    strcat(ScanResult, "{\"end\":true}]");
}

/* An HTTP GET handler */
// static esp_err_t hello_get_handler(httpd_req_t *req)
// {
//     char*  buf;
//     size_t buf_len;

//     /* Get header value string length and allocate memory for length + 1,
//      * extra byte for null termination */
//     buf_len = httpd_req_get_hdr_value_len(req, "Host") + 1;
//     if (buf_len > 1) {
//         buf = malloc(buf_len);
//         /* Copy null terminated value string into buffer */
//         if (httpd_req_get_hdr_value_str(req, "Host", buf, buf_len) == ESP_OK) {
//             ESP_LOGI(TAG, "Found header => Host: %s", buf);
//         }
//         free(buf);
//     }

//     buf_len = httpd_req_get_hdr_value_len(req, "Test-Header-2") + 1;
//     if (buf_len > 1) {
//         buf = malloc(buf_len);
//         if (httpd_req_get_hdr_value_str(req, "Test-Header-2", buf, buf_len) == ESP_OK) {
//             ESP_LOGI(TAG, "Found header => Test-Header-2: %s", buf);
//         }
//         free(buf);
//     }

//     buf_len = httpd_req_get_hdr_value_len(req, "Test-Header-1") + 1;
//     if (buf_len > 1) {
//         buf = malloc(buf_len);
//         if (httpd_req_get_hdr_value_str(req, "Test-Header-1", buf, buf_len) == ESP_OK) {
//             ESP_LOGI(TAG, "Found header => Test-Header-1: %s", buf);
//         }
//         free(buf);
//     }

//     /* Read URL query string length and allocate memory for length + 1,
//      * extra byte for null termination */
//     buf_len = httpd_req_get_url_query_len(req) + 1;
//     if (buf_len > 1) {
//         buf = malloc(buf_len);
//         if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
//             ESP_LOGI(TAG, "Found URL query => %s", buf);
//             char param[32];
//             /* Get value of expected key from query string */
//             if (httpd_query_key_value(buf, "query1", param, sizeof(param)) == ESP_OK) {
//                 ESP_LOGI(TAG, "Found URL query parameter => query1=%s", param);
//             }
//             if (httpd_query_key_value(buf, "query3", param, sizeof(param)) == ESP_OK) {
//                 ESP_LOGI(TAG, "Found URL query parameter => query3=%s", param);
//             }
//             if (httpd_query_key_value(buf, "query2", param, sizeof(param)) == ESP_OK) {
//                 ESP_LOGI(TAG, "Found URL query parameter => query2=%s", param);
//             }
//         }
//         free(buf);
//     }

//     /* Set some custom headers */
//     httpd_resp_set_hdr(req, "Custom-Header-1", "Custom-Value-1");
//     httpd_resp_set_hdr(req, "Custom-Header-2", "Custom-Value-2");

//     /* Send response with custom headers and body set as the
//      * string passed in user context*/
//     const char* resp_str = (const char*) req->user_ctx;
//     httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);

//     /* After sending the HTTP response the old HTTP request
//      * headers are lost. Check if HTTP request headers can be read now. */
//     if (httpd_req_get_hdr_value_len(req, "Host") == 0) {
//         ESP_LOGI(TAG, "Request headers lost");
//     }
//     return ESP_OK;
// }

// static const httpd_uri_t hello = {
//     .uri       = "/hello",
//     .method    = HTTP_GET,
//     .handler   = hello_get_handler,
//     /* Let's pass response string in user
//      * context to demonstrate it's usage */
//     .user_ctx  = "Hello World!"
// };

// /* An HTTP POST handler */
// static esp_err_t echo_post_handler(httpd_req_t *req)
// {
//     char buf[100];
//     int ret, remaining = req->content_len;

//     while (remaining > 0) {
//         /* Read the data for the request */
//         if ((ret = httpd_req_recv(req, buf,
//                         MIN(remaining, sizeof(buf)))) <= 0) {
//             if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
//                 /* Retry receiving if timeout occurred */
//                 continue;
//             }
//             return ESP_FAIL;
//         }

//         /* Send back the same data */
//         httpd_resp_send_chunk(req, buf, ret);
//         remaining -= ret;

//         /* Log data received */
//         ESP_LOGI(TAG, "=========== RECEIVED DATA ==========");
//         ESP_LOGI(TAG, "%.*s", ret, buf);
//         ESP_LOGI(TAG, "====================================");
//     }
//     ESP_LOGI(TAG, "=========== RECEIVED OVER! ==========");
//     // End response
//     httpd_resp_send_chunk(req, NULL, 0);
//     return ESP_OK;
// }

// static const httpd_uri_t echo = {
//     .uri       = "/echo",
//     .method    = HTTP_POST,
//     .handler   = echo_post_handler,
//     .user_ctx  = NULL
// };

esp_err_t http_404_error_handler(httpd_req_t *req, httpd_err_code_t err)
{
    if (strcmp("/hello", req->uri) == 0) {
        httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "/hello URI is not available");
        /* Return ESP_OK to keep underlying socket open */
        return ESP_OK;
    } else if (strcmp("/echo", req->uri) == 0) {
        httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "/echo URI is not available");
        /* Return ESP_FAIL to close underlying socket */
        return ESP_FAIL;
    }
    /* For any other URI send 404 and close socket */
    httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "Some 404 error message");
    return ESP_FAIL;
}

// static esp_err_t ctrl_put_handler(httpd_req_t *req)
// {
//     char buf;
//     int ret;

//     if ((ret = httpd_req_recv(req, &buf, 1)) <= 0) {
//         if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
//             httpd_resp_send_408(req);
//         }
//         return ESP_FAIL;
//     }

//     if (buf == '0') {
//         /* URI handlers can be unregistered using the uri string */
//         ESP_LOGI(TAG, "Unregistering /hello and /echo URIs");
//         httpd_unregister_uri(req->handle, "/hello");
//         httpd_unregister_uri(req->handle, "/echo");
//         /* Register the custom error handler */
//         httpd_register_err_handler(req->handle, HTTPD_404_NOT_FOUND, http_404_error_handler);
//     }
//     else {
//         ESP_LOGI(TAG, "Registering /hello and /echo URIs");
//         httpd_register_uri_handler(req->handle, &hello);
//         httpd_register_uri_handler(req->handle, &echo);
//         /* Unregister custom error handler */
//         httpd_register_err_handler(req->handle, HTTPD_404_NOT_FOUND, NULL);
//     }

//     /* Respond with empty body */
//     httpd_resp_send(req, NULL, 0);
//     return ESP_OK;
// }

// static const httpd_uri_t ctrl = {
//     .uri       = "/ctrl",
//     .method    = HTTP_PUT,
//     .handler   = ctrl_put_handler,
//     .user_ctx  = NULL
// };



static esp_err_t www_configPage_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "text/html");
    httpd_resp_send(req, configPage, strlen(configPage));
    return ESP_OK;
}

static const httpd_uri_t www_configPage = {
    .uri       = "/",
    .method    = HTTP_GET,
    .handler   = www_configPage_handler,
    .user_ctx  = NULL
};

esp_err_t _scan(httpd_req_t *req)
{
    ESP_LOGE(TAG, "_scan");

    //ScanResult = (char*)malloc(512);
    
    // if (ScanResult == NULL)
    // {
    //     httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Scan failed!");
    //     return ESP_FAIL;
    // }
    //memset(ScanResult,0,512);
    wifi_scan_again_ssid();
    httpd_resp_set_type(req, "text/plain");
    httpd_resp_send(req, (const char*)ScanResult, strlen(ScanResult));
    ESP_LOGI(TAG, "%s",ScanResult);
    free(ScanResult);
    ScanResult = NULL;
    return ESP_OK;
}
static esp_err_t www_getData_handler(httpd_req_t *req)
{
    
    return _scan(req);
}

static const httpd_uri_t www_getData = {
    .uri       = "/getData",
    .method    = HTTP_GET,
    .handler   = www_getData_handler,
    .user_ctx  = NULL
};
static esp_err_t www_getNewData_handler(httpd_req_t *req)
{
    return _scan(req);
}

static const httpd_uri_t www_getNewData = {
    .uri       = "/getNewData",
    .method    = HTTP_GET,
    .handler   = www_getNewData_handler,
    .user_ctx  = NULL
};

char configWiFi_ssid[32];
char configWiFi_pwd[32];
esp_err_t get_URL_arg(httpd_req_t *req)
{
    char* buf;
    size_t buf_len = httpd_req_get_url_query_len(req) + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
            /* Get value of expected key from query string */
            if (httpd_query_key_value(buf, "ssid", configWiFi_ssid, sizeof(configWiFi_ssid)) == ESP_OK) {
                ESP_LOGI(TAG, "configWiFi_ssid=%s", configWiFi_ssid);
            }
            if (httpd_query_key_value(buf, "pwd", configWiFi_pwd, sizeof(configWiFi_pwd)) == ESP_OK) {
                ESP_LOGI(TAG, "configWiFi_pwd=%s", configWiFi_pwd);
            }
        }
        free(buf);
        return ESP_OK;
    }
    return ESP_FAIL;
}
extern esp_err_t nvs_save_str(char* key, char* value);
extern esp_err_t nvs_read_str(char* key, char* value);
extern esp_err_t wifi_connect(char* ssid, char* pwd);

void Wificonfig_save_nvs(char* ssid, char* pwd)
{
//    nvs_save_str("wifi_cfg_ssid",ssid);
//    nvs_save_str("wifi_cfg_pwd" ,pwd);
}

void Wificonfig_read_nvs(char* ssid, char* pwd)
{
//    nvs_read_str("wifi_cfg_ssid",ssid);
//    nvs_read_str("wifi_cfg_pwd" ,pwd);
}



static esp_err_t www_handleData_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "text/plain");
    get_URL_arg(req);
    const char* state = "{\"status\":true}";
    httpd_resp_send(req, state, strlen(state));
    
    if(wifi_connect(configWiFi_ssid, configWiFi_pwd) == ESP_OK)
    {
        Wificonfig_save_nvs(configWiFi_ssid, configWiFi_pwd);
    }
    else{
        char* state = "{\"status\":false}";
        httpd_resp_send(req, state, strlen(state));
    }
    return ESP_OK;
}

static const httpd_uri_t www_handleData = {
    .uri       = "/ssidData",
    .method    = HTTP_GET,
    .handler   = www_handleData_handler,
    .user_ctx  = NULL
};

// static esp_err_t favicon_ico_handler(httpd_req_t *req)
// {
//     httpd_resp_set_type(req, "text/plain");
//     httpd_resp_send(req, "OK", strlen("OK"));
//     return ESP_OK;
// }

// static const httpd_uri_t www_favicon_ico = {
//     .uri       = "/favicon.ico",
//     .method    = HTTP_GET,
//     .handler   = favicon_ico_handler,
//     .user_ctx  = NULL
// };

static httpd_handle_t start_webserver(void)
{
    httpd_handle_t server = NULL;
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();
    config.lru_purge_enable = true;

    // Start the httpd server
    ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
    if (httpd_start(&server, &config) == ESP_OK) {
        // Set URI handlers
        ESP_LOGI(TAG, "Registering URI handlers");
        // httpd_register_uri_handler(server, &hello);
        // httpd_register_uri_handler(server, &echo);
        // httpd_register_uri_handler(server, &ctrl);
        httpd_register_uri_handler(server, &www_configPage);
        httpd_register_uri_handler(server, &www_getData);
        httpd_register_uri_handler(server, &www_getNewData);
        httpd_register_uri_handler(server, &www_handleData);
        //httpd_register_uri_handler(server, &www_favicon_ico);
        
        return server;
    }

    ESP_LOGE(TAG, "Error starting server!");
    return NULL;
}

static esp_err_t stop_webserver(httpd_handle_t server)
{
    // Stop the httpd server
    return httpd_stop(server);
}

static void disconnect_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data)
{
    httpd_handle_t* server = (httpd_handle_t*) arg;
    if (*server) {
        ESP_LOGI(TAG, "Stopping webserver");
        if (stop_webserver(*server) == ESP_OK) {
            *server = NULL;
        } else {
            ESP_LOGE(TAG, "Failed to stop http server");
        }
    }
}

static void connect_handler(void* arg, esp_event_base_t event_base,
                            int32_t event_id, void* event_data)
{
    httpd_handle_t* server = (httpd_handle_t*) arg;
    if (*server == NULL) {
        ESP_LOGI(TAG, "Starting webserver");
        *server = start_webserver();
    }
}

void esp_wifi_webserver(void)
{
    static httpd_handle_t server = NULL;


#ifdef CONFIG_EXAMPLE_CONNECT_WIFI
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &connect_handler, &server));
    //ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &disconnect_handler, &server));
#endif // CONFIG_EXAMPLE_CONNECT_WIFI

    /* Start the server for the first time */
    //tcpip_adapter_init();
    server = start_webserver();
}